﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ABII.AdminPanel
{
    public class AuthenticationException : Exception
    {
        public AuthenticationException(String message) : base(message)
        {
        }
    }
    public class AuthRequiredException : AuthenticationException
    {
        public AuthRequiredException(String message) : base(message)
        {
        }
    }
    public class Record
    {
        public Int32 ID { get; private set; }
        public String Name { get; private set; }

        public Record(Int32 id, String name)
        {
            ID = id;
            Name = name;
        }
    }
    public enum RIGHTS
    {
        NONE, 
        LOOK, 
        MODIFY
    }
    public class DataField<T>
    {
        public RIGHTS Rights { get; set; }
        public T Name { get; set; }

        public DataField()
        {
            Rights = RIGHTS.NONE;
            Name = default(T);
        }

        public DataField(RIGHTS rights, T name)
        {
            Rights = rights;
            Name = (Rights != RIGHTS.NONE) ? name : default(T);
        }
    }
    public class SecurityData
    {
        public DataField<String> Username { get; set; }
        public DataField<String> Password { get; set; }
        public DataField<String> Rank { get; set; }
        public DataField<String> Gender { get; set; }
        public DataField<DateTime> Birthday { get; set; }
        public DataField<String> Question { get; set; }
        public DataField<String> Answer { get; set; }

        public SecurityData()
        {
            Username = Password = Rank = Gender = Question = Answer = null;
            Birthday = null;
        }

        public SecurityData(DataField<String> username, DataField<String> password, DataField<String> rank, DataField<String> gender, DataField<DateTime> birthday, DataField<String> question, DataField<String> answer)
        {
            Username = username;
            Password = password;
            Rank = rank;
            Gender = gender;
            Birthday = birthday;
            Question = question;
            Answer = answer;
        }
    }
    public class Database
    {
        public Int32 RankID { get; private set; }
        public List<Record> Ranks { get; private set; }
        public List<Record> Users { get; private set; }
        public List<Record> Genders { get; private set; }
        public List<Record> States { get; private set; }

        public Database()
        {
            RankID = 0;
            Ranks = new List<Record>();
            Users = new List<Record>();
            Genders = new List<Record>();
            States = new List<Record>();
        }

        public void Authenticate(String username, String password)
        {
            if (!(IsValidCredential(username) && IsValidCredential(password)))
            {
                throw new AuthenticationException("Invalid username/password!" + Environment.NewLine + 
                                                  "Usernames and passwords contains only upper and lowercase letter, " + Environment.NewLine + 
                                                  "digits and underlines (maximum 16 characters long)!");
            }
            RankID = Queries.Authenticate(username, password);
            if (RankID == 0 || RankID > 3)
            {
                throw new AuthenticationException("Invalid username/password or the user does not have access rights to this client!");
            }
        }

        public static Boolean CanLook(RIGHTS right)
        {
            return (right & RIGHTS.LOOK) == RIGHTS.LOOK;
        }

        public static Boolean CanModify(RIGHTS right)
        {
            return (right & RIGHTS.MODIFY) == RIGHTS.MODIFY;
        }

        public void GetPublicData()
        {
            Validate();
            Ranks = Queries.GetRanks();
            Users = Queries.GetUsers();
        }

        public SecurityData GetSecurityData(String username, Int32 rankID)
        {
            Validate();
            SecurityData data = Queries.GetSecurityData(username);
            data.Username.Rights = GetUsernameRights(GetDefaultRights(rankID));
            data.Password.Rights = RIGHTS.NONE;
            data.Rank.Rights = RIGHTS.LOOK | RIGHTS.MODIFY;
            data.Gender.Rights = RIGHTS.LOOK | RIGHTS.MODIFY;
            data.Birthday.Rights = RIGHTS.LOOK | RIGHTS.MODIFY;
            data.Question.Rights = RIGHTS.LOOK;
            data.Answer.Rights = RIGHTS.NONE;
            return data;
        }

        private RIGHTS GetDefaultRights(Int32 rankID)
        {
            RIGHTS right = RIGHTS.NONE;
            if (RankID == rankID)
            {
                right |= RIGHTS.LOOK;
            }
            if (RankID >= rankID)
            {
                right |= RIGHTS.MODIFY;
            }
            return right;
        }

        private RIGHTS GetUsernameRights(RIGHTS right)
        {
            if (right != RIGHTS.NONE)
            {
            }
            return right;
        }

        public Int32 GetUserRank(String username)
        {
            return Users.Find(user => user.Name.Equals(username)).ID;
        }

        public void Disconnect()
        {
            RankID = 0;
            Ranks.Clear();
            Users.Clear();
            Genders.Clear();
            States.Clear();
        }

        public Boolean CanSee(Int32 rankID)
        {
            return true;
        }

        private void Validate()
        {
            if (RankID == 0 || RankID > 3)
            {
                throw new AuthRequiredException("Authentication required for this task!");
            }
        }

        private Boolean IsValidCredential(String username)
        {
            return Regex.IsMatch(username, "^[a-zA-Z0-9_]{4,16}$");
        }
    }
}
